package com.inartar.yn;

import android.content.Context;

import com.inartar.effect.Constraints;
import com.inartar.effect.YNBeautyEffect;
import com.inartar.effect.YNCuteEffect;
import com.inartar.effect.YNEffect;
import com.inartar.effect.YNEffectEngine;
import com.inartar.effect.YNLandscapeEffect;
import com.inartar.effect.YNSharpenEffect;
import com.inartar.effect.YNSlenderEffect;
import com.inartar.yn.utils.Accelerometer;
import com.xiusdk.ynfacetrack.YNFace;
import com.xiusdk.ynfacetrack.YNFaceTrack;

import java.util.ArrayList;
import java.util.List;

public class YNRenderer {

    private YNFaceTrack mTracker = null;
    private YNEffectEngine mEngine = null;

    private boolean mFrontFacing = false;
    private int mOrientation = 0;
    private Context mContext;
    private YNBeautyEffect mBeautyEffect = null;
    private YNLandscapeEffect mLandscapeEffect = null;
    private YNSlenderEffect mSlenderEffect = null;
    private boolean mEffectChanged = false;
    private List<Runnable> mRunnableList = new ArrayList<>();
    private EffectItem mEffectItem;
    private int mBeautyIntensity = 80;
    private int mSlenderIntensity = 80;
    private int mLandscapeIntensity = 80;

    public YNRenderer(Context context)
    {
        mTracker = new YNFaceTrack(context, 0);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        if( mTracker != null )
        {
            mTracker.destory();
            mTracker = null;
        }
    }

    public int onDrawFrame(int textureId, byte[] buffer, int width, int height)
    {

        /**
         * 获取重力传感器返回的方向
         */
        int dir = Accelerometer.getDirection();

        /**
         * 请注意前置摄像头与后置摄像头旋转定义不同
         * 请注意不同手机摄像头旋转定义不同
         */
        if (mFrontFacing &&
                ((mOrientation == Constraints.YN_CLOCKWISE_ROTATE_270 && (dir & 1) == 1) ||
                        (mOrientation == Constraints.YN_CLOCKWISE_ROTATE_90 && (dir & 1) == 0)))
            dir = (dir ^ 2);

        YNFace[] faces = null;
        try {
            faces = mTracker != null ? mTracker.track(buffer, 0, width, height, width, dir) : null;
            synchronized (this) {
                if (mEngine != null) {

                    if( mEffectChanged == true)
                    {
                        mEffectChanged = false;
                        onEffectChanged();
                    }

                    int result = mEngine.processI420BiPlanar(buffer, width, width, height, mOrientation, mFrontFacing ? Constraints.YN_FLIP_HORIZONTAL : 0, faces);

                    return result;
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return textureId;
    }

    public void onSurfaceCreated()
    {
        synchronized (this) {
            if (mEngine != null) {
                mEngine.Release();
                mEngine = null;
            }
            mEngine = new YNEffectEngine();
            mEffectChanged = true;
        }
    }

    public void onSurfaceDestroyed()
    {
        synchronized (this) {
            if (mEngine != null) {
                mEngine.Release();
                mEngine = null;
            }
        }
    }

    public void onCameraChange(int facing, int orientation)
    {
        mFrontFacing = facing == 1;
        switch (orientation)
        {
            case 90:
                mOrientation = Constraints.YN_CLOCKWISE_ROTATE_90;
                break;
            case 180:
                mOrientation = Constraints.YN_CLOCKWISE_ROTATE_180;
                break;
            case 270:
                mOrientation = Constraints.YN_CLOCKWISE_ROTATE_270;
                break;
            case 0:
            default:
                mOrientation = Constraints.YN_CLOCKWISE_ROTATE_0;
                break;
        }
    }

    public void setSlenderIntensity(int intensity)
    {
        synchronized (this) {
            if(mSlenderEffect != null)
            {
                mSlenderEffect.setIntensity(intensity);
                mSlenderEffect.setEyeBigIntensity(intensity);
            }
            mSlenderIntensity = intensity;
        }
    }

    public void setBeautyIntensity(int intensity)
    {
        synchronized (this) {
            if(mBeautyEffect != null)
            {
                mBeautyEffect.setIntensity(intensity);
            }
            mBeautyIntensity = intensity;
        }
    }

    public void setLandscapeIntensity(int intensity)
    {
        synchronized (this) {
            if(mLandscapeEffect != null)
            {
                mLandscapeEffect.setIntensity(intensity);
            }
            mLandscapeIntensity = intensity;
        }
    }

    public void setEffectItem(EffectItem item) {
        synchronized (this) {
            mEffectItem = item;
            mEffectChanged = true;
        }
    }

    private void onEffectChanged()
    {
        YNBeautyEffect beautyEffect = null;
        YNLandscapeEffect landscape = null;
        YNSlenderEffect slender = null;
        List<YNEffect> effects = new ArrayList<YNEffect>();
        if( mEffectItem != null) {
            for (String effectName : mEffectItem.getEffects()) {
                YNEffect effect = null;
                if (effectName.equalsIgnoreCase("cute")) {
                    effect = new YNCuteEffect();
                }
                if (effectName.equalsIgnoreCase("beauty")) {
                    beautyEffect = new YNBeautyEffect();
                    effect = beautyEffect;
                } else if (effectName.equalsIgnoreCase("landscape")) {
                    landscape = new YNLandscapeEffect();
                    effect = landscape;
                } else if (effectName.equalsIgnoreCase("slender")) {
                    slender = new YNSlenderEffect();
                    effect = slender;
                } else if (effectName.equalsIgnoreCase("sharpen")) {
                    effect = new YNSharpenEffect();
                }
                if (effect != null) {
                    effect.setConfigPath(mEffectItem.Path + "/" + effectName + ".json");
                    effects.add(effect);
                }
            }
            mBeautyEffect = beautyEffect;
            mLandscapeEffect = landscape;
            mSlenderEffect = slender;
            if(mSlenderEffect != null)
            {
                mSlenderEffect.setIntensity(mSlenderIntensity);
                mSlenderEffect.setEyeBigIntensity(mSlenderIntensity);
            }
            if(mLandscapeEffect != null)
            {
                mLandscapeEffect.setIntensity(mLandscapeIntensity);
            }
            if(mBeautyEffect != null)
            {
                mBeautyEffect.setIntensity(mBeautyIntensity);
            }
            mEngine.addEffects(effects, true);
        }
        else
        {
            mBeautyEffect = null;
            mLandscapeEffect = null;
            mSlenderEffect = null;
            mEngine.removeAllEffects();
        }
    }
}
